package com.example.demo.crc16;

import cn.hutool.core.util.ByteUtil;
import cn.hutool.core.util.HexUtil;

public class Test {

    public static void main(String[] args) {
        System.out.println(genCommandByteCrc("80", 6, 1, "FN&&A&&u1&&13236835221&&u2&&15124180920&&&&##"));
    }

    // CRC16 / X25 多项式校验和
    public static int Crc16(byte [] bytes) {
        return Crc16(bytes, 0, bytes.length);
    }
    public static int Crc16(byte [] bytes, int startIdx, int len) {
        int i, j, lsb;
        int h = 0xffff;
        for (i = 0; i < len; i++) {
            h ^= (bytes[startIdx+i] & 0xff);
            h &= 0xffff;
            for (j = 0; j < 8; j++) {
                lsb = h & 0x0001; //取 CRC 的移出位
                h >>= 1;
                if (lsb == 1) {
                    h ^= 0x8408;
                    h &= 0xffff;
                }
            }
        }
        h ^= 0xffff;
        return h;
    }

    /**
     * 计算指令CRC
     * @param cmdId 指令号
     * @param seqNum 消息序列号
     * @param flag 服务器标识
     * @param msg 指令内容
     */
    public static int genCommandByteCrc(String cmdId, int seqNum, int flag, String msg) {

        byte[] bodyBytes = genCommandByte(flag, msg);
        // 拼接帧
        byte[] frameBuf;
        int bodyLen = bodyBytes.length + 5;
        byte[] bodyLenBytes;

        // init frameBuf
        frameBuf = new byte[4 + 1 + bodyLen];
        // start pos
        byte[] startDelimiterBytes = HexUtil.decodeHex("7878");
        System.arraycopy(startDelimiterBytes, 0, frameBuf, 0 , 2);
        // body length num
        frameBuf[2] = (byte) bodyLen;
        bodyLenBytes = new byte[]{(byte) bodyLen};

        // cmd code
        frameBuf[2 + bodyLenBytes.length] = HexUtil.decodeHex(cmdId)[0];

        // body
        System.arraycopy(bodyBytes, 0, frameBuf, 3 + bodyLenBytes.length, bodyBytes.length);

        // seq num
        byte[] seqNumBytes = ByteUtil.intToBytes(seqNum);
        System.arraycopy(seqNumBytes, 2, frameBuf, 3 + bodyLenBytes.length + bodyBytes.length, 2);

        // crc16
        return Crc16(frameBuf, 2, frameBuf.length - 6);
    }

    public static byte[] genCommandByte(int flag, String msg) {
        byte[] msgBytes = msg.getBytes();
        int len = 4 + msgBytes.length + 2;
        byte[] buf = new byte[len + 1];
        buf[0] = (byte)len;
        byte[] flagBytes = ByteUtil.intToBytes(flag);
        System.arraycopy(flagBytes, 0, buf, 1, 4);
        System.arraycopy(msgBytes, 0, buf, 5, msgBytes.length);
        buf[len] = 0x01;
        return buf;
    }
}
